package org.apache.ibatis.common.logging;

import com.sun.org.apache.xpath.internal.operations.Or;
import org.apache.ibatis.common.logging.jarkata.JakartaCommonsLoggingImpl;
import org.apache.ibatis.common.logging.jdk14.Jdk14LoggingImpl;
import org.apache.ibatis.common.logging.log4j.Log4jImpl;
import org.apache.ibatis.common.logging.log4j2.Log4j2Impl;
import org.apache.ibatis.common.logging.nologging.NoLoggingImpl;
import org.apache.ibatis.common.logging.slf4j.Slf4jImpl;
import org.apache.ibatis.common.logging.stdout.StdOutImpl;

import java.lang.reflect.Constructor;

/**
 * @Name LogFactory
 * @Description: 日志工厂
 * 描述信息：我们知道 Log 接口有着众多的实现类，而日志工厂就是制造日志实现类的工厂。
 * @Version v1.0.0
 * @Author: lichao
 * @Date: 2024-05-14 16:42:53
 **/
public final class LogFactory {
    // 支持标记的日志框架实现类所使用的标记
    public static final String MARKER = "MYBATIS";
    private static Constructor<? extends Log> logConstructor;

    private LogFactory() {
    }

    static {
        tryImplementation(LogFactory::useSlf4jLogging);
        tryImplementation(LogFactory::useCommonsLogging);
        tryImplementation(LogFactory::useLog4j2Logging);
        tryImplementation(LogFactory::useLog4jLogging);
        tryImplementation(LogFactory::useJdk14Logging);
        tryImplementation(LogFactory::useNoLogging);
    }

    /**
     * 尝试实现一个日志实例
     *
     * @param runnable 用来尝试实现日志实例的操作
     * @version v1.0.0
     * @author lichao
     * @date 2024-05-15 16:17:06
     */
    private static void tryImplementation(Runnable runnable) {
        if (logConstructor == null) {
            try {
                runnable.run();
            } catch (Throwable e) {
                // 忽略
            }
        }
    }

    public static synchronized void useSlf4jLogging() {
        setImplementation(Slf4jImpl.class);
    }

    public static synchronized void useCommonsLogging() {
        setImplementation(JakartaCommonsLoggingImpl.class);
    }

    public static synchronized void useLog4j2Logging() {
        setImplementation(Log4j2Impl.class);
    }

    public static synchronized void useLog4jLogging() {
        setImplementation(Log4jImpl.class);
    }

    public static synchronized void useJdk14Logging() {
        setImplementation(Jdk14LoggingImpl.class);
    }

    public static synchronized void useStdOutLogging() {
        setImplementation(StdOutImpl.class);
    }

    public static synchronized void useNoLogging() {
        setImplementation(NoLoggingImpl.class);
    }

    private static void setImplementation(Class<? extends Log> implClass) {
        try {
            Constructor<? extends Log> candidate = implClass.getConstructor(String.class);
            Log log = candidate.newInstance(LogFactory.class.getName());
            if (log.isDebugEnabled()) {
                String msg = "实例化日志实现类 [" + implClass + "]";
                log.debug(msg);
            }
            // 如果运行到这里，说明没有发生异常，实例化日志实现类成功。
            logConstructor = candidate;
        } catch (Throwable e) {
            throw new LogException("实例化日志实现类失败，原因：" + e, e);
        }
    }

    public static Log getLog(Class<?> clazz) {
        return getLog(clazz.getName());
    }

    private static Log getLog(String logger) {
        try {
            return logConstructor.newInstance(logger);
        } catch (Throwable e) {
            throw new LogException("实例化日志实现类 [" + logger + "] 失败，原因：" + e, e);
        }
    }

}

